package com.xt.core.helper.data;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.Iterator;

import javax.persistence.Query;

import org.hibernate.Hibernate;
import org.hibernate.type.Type;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Disjunction;


import com.xt.core.BaseConstants;


/**
* <p>the helper for genarate sql string
*
* @author txiao
* @version Revision: 1.0, Date: 30.10.2009
*/
public class HibernateFormatUtil {


	/*********************** set criteria **************************/
	public static DetachedCriteria buildOrder(DetachedCriteria crit, LinkedHashMap<String, String> order) {
		if (order != null && order.size() > 0) {
			for (String key : order.keySet()) {
				if(BaseConstants.ORDERASC.equals(order.get(key))){
					crit.addOrder(Order.asc(key).ignoreCase());
				}else{
					crit.addOrder(Order.desc(key).ignoreCase());
				}
			}
		}
		return crit;
	}
	
	/**
	 * add an order to order list
	 * 
	 * @param order
	 * @param field
	 * @param value
	 */
	public static void addOrder(LinkedHashMap<String, String> order, String field, String value){
		order.put(field, value);
	}
	
	
	/**
	 * add one condition 
	 * 
	 * @param queryParams
	 * @param field
	 * @param value
	 * @param type
	 */
	public static void addOneCondition(Set<LinkedHashMap<String, Object>> queryParams, String field, Object value, String type){
		LinkedHashMap<String, Object> oneCondition = new LinkedHashMap<String, Object>();
		oneCondition.put(BaseConstants.QUERY_FIELD, field);
		oneCondition.put(BaseConstants.QUERY_VALUE, value);
		oneCondition.put(BaseConstants.QUERY_TYPE, type);
		queryParams.add(oneCondition);
	}
	
	
	/**
	 * add one or condition to the or-condition-set
	 * @param queryParams
	 * @param field
	 * @param value
	 * @param type
	 */
	public static void addOneOrCondition(Set<LinkedHashMap<String, Object>> oneOrConditionSet, String field, Object value, String type){
		LinkedHashMap<String, Object> oneCondition = new LinkedHashMap<String, Object>();
		oneCondition.put(BaseConstants.OR_FIELD, field);
		oneCondition.put(BaseConstants.OR_VALUE, value);
		oneCondition.put(BaseConstants.OR_TPYE, type);
		oneOrConditionSet.add(oneCondition);
	}
	
	/**
	 * add all conditions to criteria
	 * 
	 * @param crit
	 * @param queryParams
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static DetachedCriteria buildQuery(DetachedCriteria crit, Set<LinkedHashMap<String, Object>> queryParams) {
		if (queryParams != null && queryParams.size() > 0) {
			for (LinkedHashMap<String, Object> oneCondition : queryParams) {
				String type = (String) oneCondition.get(BaseConstants.QUERY_TYPE);
				String fieldName = (String) oneCondition.get(BaseConstants.QUERY_FIELD);
				Object value = (Object) oneCondition.get(BaseConstants.QUERY_VALUE);
				if(BaseConstants.TYPE_ALIAS.equals(type)){
					crit.createAlias(fieldName, (String) value);
				}else if(BaseConstants.TYPE_EQ.equals(type)){
					crit.add(Restrictions.eq(fieldName, value));
				}else if(BaseConstants.TYPE_LIKE.equals(type)){
					crit.add(Restrictions.like(fieldName, (String)value, MatchMode.ANYWHERE).ignoreCase());
				}else if(BaseConstants.TYPE_GE.equals(type)){
					crit.add(Restrictions.ge(fieldName, value));
				}else if(BaseConstants.TYPE_LE.equals(type)){
					crit.add(Restrictions.le(fieldName, value));
				}else if(BaseConstants.TYPE_OR.equals(type)){
					buildOr(crit, (Set<LinkedHashMap<String, Object>>) value);
				}else{
					
				}
			}
		}
		return crit;
	}
	
	/**
	 * build one or query
	 * one set is a "or" disjunction
	 * every set value composed by three attributes: value, fieldName, condition type
	 * 
	 * @param crit
	 * @param queryParams
	 * @return
	 */
	public static DetachedCriteria buildOr(DetachedCriteria crit, Set<LinkedHashMap<String, Object>> oneOrSet){
		if (oneOrSet != null && oneOrSet.size() > 0) {
			Disjunction disjunction = Restrictions.disjunction();
				
			for(LinkedHashMap<String, Object> oneRestrict: oneOrSet){
				Object value = (Object) oneRestrict.get(BaseConstants.OR_VALUE);
				String fieldName = (String) oneRestrict.get(BaseConstants.OR_FIELD);
				String type = (String) oneRestrict.get(BaseConstants.OR_TPYE);
				
				//depend on condition type, 
				//like supports only String object type!!!
				if(BaseConstants.TYPE_EQ.equals(type)){
					disjunction.add(Restrictions.eq(fieldName, value));
				}else if(BaseConstants.TYPE_GE.equals(type)){
					disjunction.add(Restrictions.ge(fieldName, value));
				}else if(BaseConstants.TYPE_LE.equals(type)){
					disjunction.add(Restrictions.le(fieldName, value));
				}else if(BaseConstants.TYPE_LIKE.equals(type)){
					//Restrictions.like(key, queryParams.get(key)+"%")
					disjunction.add(Restrictions.like(fieldName, (String)value, MatchMode.ANYWHERE).ignoreCase());
				}else{
					disjunction.add(Restrictions.eq(fieldName, value));
				}
			}
				
			crit.add(disjunction);
		}
		return crit;
	}
	
	
	/**
	 * !!!!under contruction!!!
	 * add sqlRestriction query
	 * 
	 * @param crit
	 * @param sqlString
	 * @return
	 */
	//using sql restriction
	@SuppressWarnings("unchecked")
	public static DetachedCriteria buildSqlRestriction(DetachedCriteria crit, LinkedHashMap<String, Object> queryParams){
		if (queryParams != null && queryParams.size() > 0) {
			for (String key : queryParams.keySet()){
				LinkedHashMap<String, Object> oneRestrict= (LinkedHashMap<String, Object>) queryParams.get(key);
				String sqlString = (String) oneRestrict.get(BaseConstants.SQLRESTRICTIONSTRING);
				Object[] values = (Object[]) oneRestrict.get(BaseConstants.SQLRESTRICTIONVALUES);
				Type[] types = (Type[]) oneRestrict.get(BaseConstants.SQLRESTRICTIONTYPES);
				crit.add(Restrictions.sqlRestriction(sqlString, values, types));
			}
		}
		return crit;
	}
	
	/*********************** set query parameters **************************/
	/**
	 * set query's parameters using HashMap
	 * @param query
	 * @param queryParams
	 */
	public static void setQueryParam(Query query, Object[] queryParams) {
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				query.setParameter(i, queryParams[i]);
			}
		}
	}
	
	
	/************ manuelly generate the hql string  ************************/
	/**
	 * format "order by" using HashMap 
	 * 
	 * @param order
	 * @return
	 */
	public static String buildOrderby(LinkedHashMap<String, String> order) {
		StringBuilder ordersql = new StringBuilder("");
		if (order != null && order.size() > 0) {
			ordersql.append(" order by ");
			for (String key : order.keySet()) {
				ordersql.append("o.").append(key).append(" ").append(
						order.get(key)).append(",");
			}
			ordersql.deleteCharAt(ordersql.length() - 1);
		}
		return ordersql.toString();
	}
	
	/**
	 * generate the query where crieria using HashMap <key,value>
	 * and relationshop is ONLY "and"
	 * @param queryParams sql query parameters
	 * @return the where string
	 */
	public static String buildQueryParam(LinkedHashMap<String, String> queryParams) {
		
		StringBuilder paramSql = new StringBuilder("");
		if (queryParams != null && queryParams.size() > 0){
			paramSql.append(" where ");
			for (String key : queryParams.keySet()) {
				/*paramSql.append("o.").append(key).append(" like '").append(
							queryParams.get(key)).append("%' and ");*/
				paramSql.append("o.").append(key).append("='").append(
						queryParams.get(key)).append("' and ");

			}
			paramSql.delete(paramSql.length()-5,paramSql.length());
		}
		
		return paramSql.toString();
	}
}
